// 交易日判断模块
// 判断是否为交易日，获取上一个交易日等

use anyhow::{Context, Result};
use chrono::{Datelike, Duration, NaiveDate, Weekday};
use serde::Deserialize;
use std::collections::HashSet;

/// 交易日历管理器
#[derive(Clone)]
pub struct TradingCalendar {
    /// 节假日集合 (YYYY-MM-DD 格式)
    pub holidays: HashSet<String>,
}

impl TradingCalendar {
    /// 创建新的交易日历
    pub fn new() -> Self {
        Self {
            holidays: Self::init_holidays(),
        }
    }
    
    /// 初始化节假日列表（2024年）
    /// 实际应用中应该从配置文件或API获取
    fn init_holidays() -> HashSet<String> {
        let mut holidays = HashSet::new();
        
        // 2024年节假日
        // 元旦: 12月30日至1月1日
        holidays.insert("2024-01-01".to_string());
        
        // 春节: 2月10日至17日
        holidays.insert("2024-02-10".to_string());
        holidays.insert("2024-02-11".to_string());
        holidays.insert("2024-02-12".to_string());
        holidays.insert("2024-02-13".to_string());
        holidays.insert("2024-02-14".to_string());
        holidays.insert("2024-02-15".to_string());
        holidays.insert("2024-02-16".to_string());
        holidays.insert("2024-02-17".to_string());
        
        // 清明节: 4月4日至6日
        holidays.insert("2024-04-04".to_string());
        holidays.insert("2024-04-05".to_string());
        holidays.insert("2024-04-06".to_string());
        
        // 劳动节: 5月1日至5日
        holidays.insert("2024-05-01".to_string());
        holidays.insert("2024-05-02".to_string());
        holidays.insert("2024-05-03".to_string());
        holidays.insert("2024-05-04".to_string());
        holidays.insert("2024-05-05".to_string());
        
        // 端午节: 6月10日
        holidays.insert("2024-06-10".to_string());
        
        // 中秋节: 9月15日至17日
        holidays.insert("2024-09-15".to_string());
        holidays.insert("2024-09-16".to_string());
        holidays.insert("2024-09-17".to_string());
        
        // 国庆节: 10月1日至7日
        holidays.insert("2024-10-01".to_string());
        holidays.insert("2024-10-02".to_string());
        holidays.insert("2024-10-03".to_string());
        holidays.insert("2024-10-04".to_string());
        holidays.insert("2024-10-05".to_string());
        holidays.insert("2024-10-06".to_string());
        holidays.insert("2024-10-07".to_string());
        
        holidays
    }
    
    /// 判断是否为交易日
    /// 
    /// 交易日定义：
    /// 1. 不是周末（周六、周日）
    /// 2. 不是法定节假日
    pub fn is_trading_day(&self, date: NaiveDate) -> bool {
        // 检查是否为周末
        if matches!(date.weekday(), Weekday::Sat | Weekday::Sun) {
            return false;
        }
        
        // 检查是否为节假日
        let date_str = date.format("%Y-%m-%d").to_string();
        if self.holidays.contains(&date_str) {
            return false;
        }
        
        true
    }
    
    /// 获取上一个交易日
    /// 
    /// 从给定日期向前查找，直到找到一个交易日
    pub fn get_previous_trading_day(&self, date: NaiveDate) -> Option<NaiveDate> {
        let mut current = date - Duration::days(1);
        
        // 最多向前查找30天
        for _ in 0..30 {
            if self.is_trading_day(current) {
                return Some(current);
            }
            current = current - Duration::days(1);
        }
        
        None
    }
    
    /// 获取下一个交易日
    pub fn get_next_trading_day(&self, date: NaiveDate) -> Option<NaiveDate> {
        let mut current = date + Duration::days(1);
        
        // 最多向后查找30天
        for _ in 0..30 {
            if self.is_trading_day(current) {
                return Some(current);
            }
            current = current + Duration::days(1);
        }
        
        None
    }
    
    /// 检查指定日期是否有数据
    /// 这里简化处理，实际应该查询数据库
    pub async fn has_data_for_date(&self, _date: NaiveDate) -> Result<bool> {
        // TODO: 实现实际的数据库查询
        // 这里暂时返回 false，表示没有数据
        Ok(false)
    }
}

impl Default for TradingCalendar {
    fn default() -> Self {
        Self::new()
    }
}

/// 从网络获取交易日历（可选功能）
pub async fn fetch_trading_calendar(year: i32) -> Result<Vec<String>> {
    // 这里可以调用第三方API获取交易日历
    // 例如：东方财富、新浪财经等
    
    // 示例：使用东方财富的交易日历接口
    let url = format!(
        "https://datacenter-web.eastmoney.com/api/data/v1/get?reportName=RPT_ECONOMY_CALENDAR&columns=ALL&filter=(CALENDAR_TYPE=\"0\")(TRADE_DATE>=\"{}-01-01\")(TRADE_DATE<=\"{}-12-31\")",
        year, year
    );
    
    let client = reqwest::Client::new();
    let response = client
        .get(&url)
        .send()
        .await
        .context("获取交易日历失败")?;
    
    #[derive(Deserialize)]
    struct ApiResponse {
        result: Option<ApiResult>,
    }
    
    #[derive(Deserialize)]
    struct ApiResult {
        data: Vec<TradingDayData>,
    }
    
    #[derive(Deserialize)]
    struct TradingDayData {
        #[serde(rename = "TRADE_DATE")]
        trade_date: String,
    }
    
    let api_response: ApiResponse = response
        .json()
        .await
        .context("解析交易日历数据失败")?;
    
    if let Some(result) = api_response.result {
        Ok(result.data.iter().map(|d| d.trade_date.clone()).collect())
    } else {
        Ok(vec![])
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_is_trading_day() {
        let calendar = TradingCalendar::new();
        
        // 测试工作日
        let workday = NaiveDate::from_ymd_opt(2024, 10, 28).unwrap();
        assert!(calendar.is_trading_day(workday));
        
        // 测试周末
        let weekend = NaiveDate::from_ymd_opt(2024, 10, 26).unwrap(); // 周六
        assert!(!calendar.is_trading_day(weekend));
        
        // 测试节假日
        let holiday = NaiveDate::from_ymd_opt(2024, 10, 1).unwrap(); // 国庆节
        assert!(!calendar.is_trading_day(holiday));
    }
    
    #[test]
    fn test_previous_trading_day() {
        let calendar = TradingCalendar::new();
        
        // 从周一获取上一个交易日（应该是上周五）
        let monday = NaiveDate::from_ymd_opt(2024, 10, 28).unwrap();
        let prev = calendar.get_previous_trading_day(monday).unwrap();
        assert_eq!(prev, NaiveDate::from_ymd_opt(2024, 10, 25).unwrap());
    }
    
    #[test]
    fn test_weekend_detection() {
        let calendar = TradingCalendar::new();
        
        // 测试周六
        let saturday = NaiveDate::from_ymd_opt(2024, 10, 26).unwrap();
        assert!(!calendar.is_trading_day(saturday));
        
        // 测试周日
        let sunday = NaiveDate::from_ymd_opt(2024, 10, 27).unwrap();
        assert!(!calendar.is_trading_day(sunday));
    }
    
    #[test]
    fn test_holiday_list_not_empty() {
        let calendar = TradingCalendar::new();
        assert!(!calendar.holidays.is_empty(), "节假日列表不应为空");
    }
    
    #[test]
    fn test_known_holidays() {
        let calendar = TradingCalendar::new();
        
        // 测试2024年国庆节
        assert!(calendar.holidays.contains("2024-10-01"), "2024-10-01 应该是节假日");
        
        // 测试2024年春节
        assert!(calendar.holidays.contains("2024-02-10"), "2024-02-10 应该是节假日");
    }
    
    #[tokio::test]
    async fn test_has_data_for_date() {
        let calendar = TradingCalendar::new();
        let date = NaiveDate::from_ymd_opt(2024, 10, 28).unwrap();
        
        // 这个测试需要数据库连接，暂时只测试方法存在
        let result = calendar.has_data_for_date(date).await;
        // 由于可能没有数据库，我们只检查方法是否能调用
        assert!(result.is_ok() || result.is_err());
    }
}
